#include "car_opr.h"
#include "rk3399_gpio_opr.h"
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/major.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/tty.h>
#include <linux/types.h>

static int	   major = 0;
static struct class* car_class;

static ssize_t gpio_write(struct file* file, const char __user* buf, size_t size, loff_t* offset) {
	char usr_cmd;
	int  err;
	err = copy_from_user(&usr_cmd, buf, 1);

	printk("set gpio status %u \n", usr_cmd);

	return 1;
}
static long car_ctrl(struct file* filp, unsigned int cmd, unsigned long arg) {

	printk(KERN_INFO "rcv cmd : %d\n",cmd);

	switch (cmd) {
	case MOVE_FORWARD:
		printk(KERN_INFO "car ctrl move forward start\n\n");
		move_forward();
		printk(KERN_INFO "car ctrl move forward end \n\n");
		break;
	case MOVE_BACKWARD:
		printk(KERN_INFO "car ctrl move backward start\n\n");
		move_backward();
		printk(KERN_INFO "car ctrl move backward end \n\n");
		break;
	case TURN_LEFT:
		printk(KERN_INFO "car turn left start\n\n");
		turn_left();
		printk(KERN_INFO "car turn left end \n\n");
		break;
	case TURN_RIGHT:
		turn_right();
		break;
	case BRAKE:
		brake();
		break;
	case SLIDE:
		slide();
		break;
	case RESTORE_DIRECTION:
		restore_direction();
		break;

	default:
		printk(KERN_ALERT "car ctrl cmd error : %d \n\n",cmd);
		break;
	}

	return 0;
}

static int car_open(struct inode* node, struct file* file) {
	car_init();	
	return 0;
}

static int car_close(struct inode* node, struct file* file) {

	return 0;
}

static struct file_operations car_opr = {
	.owner   = THIS_MODULE,
	.open    = car_open,
	.write   = gpio_write,
	.release = car_close,
	.unlocked_ioctl = car_ctrl,
};

static int __init car_module_init(void) {
	int err;

	major = register_chrdev(0, "car_dev", &car_opr); /* /dev/led */

	car_class = class_create(THIS_MODULE, "car_class");
	err       = PTR_ERR(car_class);
	if (IS_ERR(car_class)) {
		printk("error when car_module_init \n");
		unregister_chrdev(major, "car_dev");
		return -1;
	}

	device_create(car_class, NULL, MKDEV(major, 0), NULL, "car"); /* /dev/car */

	return 0;
}

static void __exit car_module_exit(void) {
	device_destroy(car_class, MKDEV(major, 0));
	class_destroy(car_class);
	unregister_chrdev(major, "car_dev");
}

module_init(car_module_init);
module_exit(car_module_exit);

MODULE_LICENSE("GPL");
